/**
 * Erzeugt die EAN aus der Medium ID, Exemplar Nummer und Standort ID
 * 
 * Datei: EAN13.java 		       	Autor: Simon Schindelmann 
 * Datum: 12.11.11                 	Version: 0.1
 * 
 */

package medienverwaltung;

import java.io.Serializable;
import java.text.DecimalFormat;

public class EAN13 implements Serializable
{
  private static final long serialVersionUID = -4572235594114331939L;
  // Mit der Zahl fangen alle EANs des Programms an
  private int instorenummer = 2;
  private long ean;

  
  public EAN13 (long ean)
  {
    if (istGueltig(ean) == true)
    {
      this.ean = ean;
    } 
    else
    {
      System.out.println ("Ungueltige EAN");
    }
  }

  
  /**
   * DecimalFormat sorgt dafuer das die Zahl mit fuehrende nullen
   * ausgefuellt wird. EAN 13 besteht aus 13 Ziffern. Der Instore Nummer
   * (1 Ziffer), der Medium Id (6 Ziffern), die StandortId (2 Ziffern)
   * und ExemplarNr (3 Ziffern) und die Pruefsumme (1 Ziffer). Damit der
   * EAN Code immer 13 Ziffern lang ist muessen die fuehrenden Nullen
   * ergaenzt werden. Waere die Medium Id 100 dann sehe sie 
   * im DecimalFormat so aus "000100".
   */ 
  public EAN13 (int medienId, int exemplarNr, int standortId)
  {
    DecimalFormat mdf, sdf, edf;
    
    mdf = new DecimalFormat ("000000");
    sdf = new DecimalFormat ("00");
    edf = new DecimalFormat ("000");
    
    // EAN ohne Pruefsumme
    Long temp = Long.parseLong (String.valueOf (instorenummer + ""
        + mdf.format (medienId) + "" + edf.format (exemplarNr) + ""
        + sdf.format (standortId)));
    
    // EAN mit Pruefsumme
    ean = Long.parseLong (String.valueOf (instorenummer + ""
        + mdf.format (medienId) + "" + edf.format (exemplarNr) + ""
        + sdf.format (standortId) + "" + pruefsummeBerechnen (temp)));
  }


  /**
   * Hier wird die Pruefsumme berechnet. Die Pruefsumme wird wie folgt
   * berechnet. Jede Zahl an einer ungeraden Stelle wird mal 1 genohmen
   * und jede Zahl an einer geraden Stelle mal 3. Die Ergebnisse werden
   * dann alle zusammen gerechnet. Die Pruefsumme ist dann der Wert der
   * drauf addiert werden muss damit die Zahl durch 10 teilbar ist.
   * Beispiel: Zahl 87 dann ist die pruefsumme 3 da 90 durch 10 teilbar
   * ist.
   * 
   * @param ean_ohnepruefsumme ist der EAN code ohne die pruefsumme
   * @return Es wird die pruefsumme zurueck gegeben.
   */
  public int pruefsummeBerechnen (long ean_ohnepruefsumme)
  {
    /*
     * Summe die sich aus der Berechnung der Zahlen an den gerade und 
     * ungeraden Stellen ergibt.
     */
    int summe = 0;
    // EAN als String
    String tmp = Long.toString (ean_ohnepruefsumme);
    // Leange der EAN
    int laenge = tmp.length ();
    // Array wo dann die zerlegte EAN hinein kommt.
    int[] array = new int[laenge];
    // Pruefsumme
    int psumme;
    
    // Zerlegung der EAN.
    for (int i = 0; i < laenge; i++)
    {
      /*
       * Mit der charAt Methode kriegen man die einzelnen Zahlen des
       * Barcodes. Die charAt-Methode liefert allerdings nur die Zahl
       * als ASCII Wert zurueck. Aber da die Zahlen von 0 - 9 die 
       * ASCII Werte von 48 - 57 sind kann man einfach die Ziffer
       * 0 abziehen die den Wert 48 hat. Zum Beispiel bei einer 2 wuerde 
       * charAt den ASCII Wert 50 zurueck gegben davon 48 abgezogen
       * hat man die 2.
       */
      array[i] = (int) ((tmp.charAt (i)) - '0');
    }
    
    // Berechnung nach dem oben schon beschriebenen Algorithmus.
    for (int j = 0; j < laenge; j++)
    {
      if ( (j + 1) % 2 == 0)
      {
        summe = summe + (3 * array[j]);
      }
      else
      {
        summe = summe + array[j];
      }
    }
    
    // Berechnung der Pruefsumme.
    if ((summe % 10) == 0)
    {
      psumme = 0;
    }
    else
    {
      psumme = 10 - (summe % 10);
    }
    return psumme;
  }
  
  /**
   * Gibt die EAN zurueck.
   * @return EAN
   */
  public long gibEAN13 ()
  {
    return ean;
  }


  /**
   * Prueft ob die ean gueltig ist. Prueft ob der ean die richtige
   * laenge hat und und guckt ob die Pruefsumme stimmt.
   * @param ean Es wird der EAN code uebergegben.
   * @return es wird true zurueck gegeben wenn code korrekt ist
   * andernfalls false
   */
  public static boolean istGueltig (long ean)
  {
    /*
     * Summe die sich aus der Berechnung der Zahlen an den gerade und 
     * ungeraden Stellen ergibt.
     */
    int summe = 0;
    // EAN als String.
    String tmp = Long.toString (ean);
    // Laenge der EAN.
    int laenge = tmp.length ();
    // Array wo dann die zerlegte EAN hinein kommt.
    int[] array = new int[laenge];
    
    // Prueft ob EAN 13 stellen Lang ist.
    if (laenge != 13)
    {
      return false;
    }
    
    // Zerlegung der EAN 
    for (int i = 0; i < laenge; i++)
    {
      /*
       * Mit der charAt Methode kriegen man die einzelnen Zahlen des
       * Barcodes. Die charAt-Methode liefert allerdings nur die Zahl
       * als ASCII Wert zurueck. Aber da die Zahlen von 0 - 9 die 
       * ASCII Werte von 48 - 57 sind kann man einfach die Ziffer
       * 0 abziehen die den Wert 48 hat. Zum Beispiel bei einer 2 wuerde 
       * charAt den ASCII Wert 50 zurueck gegben davon 48 abgezogen
       * hat man die 2.
       */
      array[i] = (int) ((tmp.charAt (i)) - '0');
    }
    
    // Verwendung des Algorithmus wie bei der EAN Erzeugung.
    for (int j = 0; j < (laenge - 1); j++)
    {
      if ( (j + 1) % 2 == 0)
      {
        summe = summe + (3 * array[j]);
      }
      else
      {
        summe = summe + array[j];
      }
    }
    
    
    /*
     * Pruefung ob der Erechnete Wert plus der Pruefsumme 0 durch 10
     * teilbar ist falls nicht wird false zurueckgegeben andernfalls
     * true
     */
    if ( (summe + array[laenge - 1]) % 10 == 0)
    {
      return true;
    }
    else
    {
      return false;
    }
  }
  
  
  /**
   * Ueberschreibung der equals Methode damit nicht die Objekte sondern
   * die EAN code in den EAAN objekten verglichen werden.
   */
  @Override
  public boolean equals (Object obj)
  {
    return this.gibEAN13 () == ((EAN13) obj).gibEAN13 ();
  }
  
  
  /**
   * Hashcode berechnung muss auch ueberschrieben werden da die equals
   * Methode ueberschrieben wird.
   */
  @Override
  public int hashCode()
  {
    return ((int) ean/100);
  }
}